#ifndef __UDP_SEVER_HPP__
#define __UDP_SEVER_HPP__

#include<iostream>
#include<string>
#include<memory>
#include<cstring>
#include<cerrno>
#include<strings.h>//bzero
#include<unistd.h>

#include"InetAddr.hpp"
#include"Log.hpp"
#include"Common.hpp"
using namespace LogModule;

//v2
using namespace LogModule;

const static int gsockfd = -1;
const static uint16_t gdefaultport = 8080;

class UdpServer
{
public:
    UdpServer(uint16_t port = gdefaultport)
        : _sockfd(gsockfd),
          _addr(port),
          _isrunning(false)
    {}

    // 都是套路
    void InitS()
    {
        // 1. 创建socket
        _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0); 
        if (_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;

        // 2. 填充网络信息（自己的），并bind绑定
        // 2.1 有没有把socket信息，设置进入内核中？？没有，只是填充了结构体！（在InetAddr中构造完成）
        

        // 2.2 bind ： 设置进入内核中
        int n = ::bind(_sockfd, _addr.NetAddr(), _addr.NetAddrLen());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
            Die(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success";
    }
    void Start()
    {
        _isrunning = true;
        while (true)
        {
            char inbuffer[1024]; // string
            struct sockaddr_in peer; //存储客户端的网络信息
            socklen_t len = sizeof(peer); // 必须设定

            ssize_t n = ::recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, CONV(&peer), &len);
            if (n > 0)
            {
                // 1. 消息内容 && 2. 谁发给我的
                InetAddr cli(peer);  //通过构造函数将客户端的网络信息网络转主机
                inbuffer[n] = 0;

                std::string clientinfo = cli.Ip() + ":" + std::to_string(cli.Port()) + " say#:  " + inbuffer;

                LOG(LogLevel::DEBUG) << clientinfo;

                std::string echo_string = "echo# ";
                echo_string += inbuffer;

                ::sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, CONV(&peer), sizeof(peer));
            }
        }
        _isrunning = false;
    }
    ~UdpServer()
    {
        if(_sockfd > gsockfd)
            ::close(_sockfd);
    }

private:
    int _sockfd;     //网络通信本质是进程间通信，还是由OS控制，通过fd操控文件
    InetAddr _addr;  //ip与port的网络与主机的地址转换
    bool _isrunning; // 服务器运行状态
};










//v1
// const static int gdefaultfd = -1;
// // const static std::string gip = "127.0.0.1";    //标识本地主机测试
// const static uint16_t gport= 8080;             //1024以上


// class UdpServer
// {
// public:
//     UdpSever(const uint16_t port = gport)
//     :_sockfd(gdefaultfd)
//     ,_port(port)
//     ,_isrunning(false)
//     {}
//     void InitS()
//     {
//         //1.创建套接字

//         /*domain:INET->网络;UNIX->本地;
//         //type:DGRAM->数据报（UDP）STREAM ->字节流（TCP）*/

//         _sockfd = ::socket(AF_INET,SOCK_DGRAM,0);//给OS填信息
//         if(_sockfd < 0)
//         {
//             LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
//             Die(2);
//         }
//         LOG(LogLevel::INFO) << "Creat socket sucess,socketfd is :  " << _sockfd;

//         //2.绑定套接字，将socket加入内核(bind函数)
//         //2.1填充IP and PORT网络信息

//         struct sockaddr_in local;
//         bzero(&local,sizeof(local));
//         local.sin_family = AF_INET;                            //给网络填信息（冷门:##连接符）sa_family_t sin_##family
//         local.sin_port = ::htons(_port);            //将端口号发给对方（网络中）（网络是大端存储），所以要转成网络序列
//         // local.sin_addr.s_addr = ::inet_addr(_ip.c_str());  //（sin_addr是一个结构体类型 ）1.ip->4bytes 2.->net order
//         local.sin_addr.s_addr = INADDR_ANY;

//         /*2.2绑定套接字与填充的信息
//         sockaddr结构体下有两种类型：//这种继承方式可以实现多态 
//         1.sockaddr_in->网络
//         2.sockaddr_un->本地
//         const struct sockaddr * _addr != sockaddr_in * 需要类型强转CONV*/

//         int n = ::bind(_sockfd,CONV(&local),sizeof(local));
//         if(n < 0)
//         {
//             LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
//             Die(3);
//         }
//         LOG(LogLevel::INFO) << "Bind socket ";

//     }
//     void Start()
//     {
//         //1.状态->启动
//         _isrunning = true;
//         while(true)
//         {
//         //2.收发消息
//             char inbuffer[1024];            //存储读到的消息
//             struct sockaddr_in peer;        
//             socklen_t len = sizeof(peer);   //两个代表发消息端信息的输出型参数，必须写
//             ssize_t n = ::recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&peer),&len);
//             if(n > 0)
//             {
//                 //2.1.1打印客户端信息
//                 uint16_t clientport = ::ntohs(peer.sin_port);     //信息需要网络转主机
//                 std::string clientip = ::inet_ntoa(peer.sin_addr);
//                 std::string clientinfo = clientip + ":" + std::to_string(clientport) + " say@: " +inbuffer;

//                 //2.1.2打印收到的消息
//                 inbuffer[n] = 0;
//                 LOG(LogLevel::DEBUG) << clientinfo;

//                 //2.2给发消息端回复
//                 std::string echo_string = "echo# :";
//                 echo_string += inbuffer;
//                 ::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,CONV(&peer),sizeof(peer));

//             }
//         }
//         _isrunning = false;
//     }
//     ~UdpSever()
//     {
//         if(_sockfd > gdefaultfd)
//         close(_sockfd);
//     }
// private:
//     int _sockfd;          //套接字在全网下标识唯一的进程（通信准确性）
//     //服务器不需要ip地址，接收该主机上任何ip地址发来的信息，只要有port[#define	INADDR_ANY ((in_addr_t) 0x00000000)]
//     //std::string _ip;    //主机（服务器）IP地址【字符串需要转换为四字节的网络ip地址（127.0.0.1）】
//     uint16_t _port;       //服务器端口号
//     bool _isrunning;      //服务器状态
// };

#endif